from ProjectTool.common_tool.db_tool.db_conf import DB_TYPES
from ProjectTool.common_tool.in_out_parameter import InParameter, URLInParameter, StepsData, FuncParameter
from django.conf import settings
from ProjectTool.common_tool.http_tool.http_request import HttpRequest
from ProjectTool.common_tool.assert_tool import AssertTool
from utils.base_response import BaseResponse
from ProjectTool.ApiTool.save_data import SaveData


api_tupe = settings.MODELS_CHOICES.get('api').get('api_type')


def get_api_status_str(api_status):
    for tp in api_tupe:
        if str(tp[0]) == str(api_status):
            return tp[1]
    return ''


class ParsingData:
    def __init__(self, serializer, queryset, data_warehouse=None, steps_data=None, cases_status=False):
        self.res = BaseResponse()
        self.serializer_info = dict(serializer(queryset).data)  # 正序列化后的数据
        self.serializer = serializer  # 序列化类
        self.queryset = queryset  # 查找到的数据
        self.cases_status = cases_status  # 是否从用例执行
        self.steps_data = steps_data if steps_data else {}  # 步骤数据
        self.show_status = queryset.show_status  # 是否将所有对比结果显示，True全部显示，False显示断言失败的数据，默认False
        self.project_db_info = self.serializer_info.get('project_db_info').get('db_info')
        self.project_db_type = self.serializer_info.get('project_db_info').get('db_type')
        self.obj_key = self.serializer_info.get('obj_key')
        self.data_warehouse = data_warehouse if isinstance(data_warehouse, dict) else {}  # 数据仓库，存取数据用的
        self.results = 3
        self.test_data = {
            'project_info': None,  # 项目明细
            'method': None,  # 接口类型
            'url': None,  # url
            'headers': None,  # 请求头数据
            'body_data': None,  # 请求体数据
            'body_sql': None,  # 处理后的请求sql
            'body_sql_dict': None,  # 要插入sql的数据
            'body_sql_data': None,  # sql运行结果
            'assert_data': None,  # 断言数据
            'assert_sql_dict': None,  # 要插入sql的数据
            'assert_sql': None,  # 处理后的sql
            'assert_sql_data': None,  # sql执行后结果
            'response_data': None,  # 响应数据
            'result_data': None,  # 对比结果
            'results':None  # 执行结果
        }
        self.data_warehouse[self.obj_key] = self.test_data
        self.get_steps_data()  # 获取步骤数据

    # 数据为字典时处理的函数
    def get_out_dict_data(self, out_data):
        if self.res.status: return
        if out_data:
            func_obj = FuncParameter(out_data)
            func_obj.run()
            out_data = func_obj.obj_data
            if func_obj.res.status:
                self.res = func_obj.res
            else:
                out_obj = StepsData(out_data, self.data_warehouse, self.steps_data)
                out_obj.run()
                if out_obj.res.status:
                    self.res = out_obj.res
                out_data = out_obj.out_data
        else:
            out_data = None
        return out_data

    # 数据为sql时的处理函数
    def get_out_sql_data(self, in_dict, sql_data):
        '''
        # 输入数据转换
        :param in_dict: 将要插入的数据
        :param sql_data: 被插入的模板
        '''
        if self.res.status: return
        if sql_data:
            out_obj = InParameter(in_dict, sql_data)
            out_obj.run()
            res = out_obj.res
            if res.status:
                self.res = res
            sql_data = out_obj.sql_data
        return sql_data

    # 执行sql,并获取执行结果
    def exe_sql_data(self, db_class, db_info, sql):
        if self.res.status: return
        db_obj = db_class(**db_info)
        sql_data = db_obj.execute_select(sql)
        db_obj.close()
        res = db_obj.res
        if res.status:
            self.res = res
        return sql_data

    # 获取步骤数据
    def get_steps_data(self):
        if not self.cases_status:
            steps_data = self.queryset.steps_data
            self.steps_data = self.get_out_dict_data(steps_data) if steps_data else {}

    # 获取项目明细
    def get_project_info(self):
        if self.res.status: return
        self.test_data['project_info'] = self.serializer_info.get('project_info')

    # 获取请求方式
    def get_method(self):
        if self.res.status: return
        api_status = self.serializer_info.get('api_type')
        self.test_data['method'] = get_api_status_str(api_status)

    # 获取URL
    def get_url(self):
        if self.res.status: return
        addr_info = self.serializer_info.get('project_info').get('addr_info')
        self.test_data['url'] = addr_info + self.serializer_info.get('url')
        if self.steps_data:
            # print("self.steps_data:",self.steps_data)
            url_dict = self.steps_data['select_data'].get('url_dict')
            out_obj = URLInParameter(self.test_data['url'], url_dict)
            out_obj.run()
            self.test_data['url'] = out_obj.out_url
            res = out_obj.res
            if res.status:
                self.res = res

    # 获取请求头
    def get_headers(self):
        if self.res.status: return
        headers = self.serializer_info.get('header_template')
        self.test_data['headers'] = self.get_out_dict_data(headers)

    # 获取请求体
    def get_body(self):
        if self.res.status: return
        sql_template = self.serializer_info.get('sql_body_info').get('sql_template') if self.serializer_info.get(
            'sql_body_info') else None  # sql模板
        if sql_template:
            request_sql_template = self.serializer_info.get('request_sql_template')  # 获取入参sql模板 是一个字典
            db_info = self.serializer_info.get('sql_body_info').get('db_info')
            db_type = self.serializer_info.get('sql_body_info').get('db_type')
            db_class = DB_TYPES.get(db_type)
            self.test_data['body_sql_dict'] = self.get_out_dict_data(request_sql_template)  # sql模板需要插入的数据
            self.test_data['body_sql'] = self.get_out_sql_data(self.test_data['body_sql_dict'], sql_template)  # 合成sql
            self.test_data['body_sql_data'] = self.exe_sql_data(db_class, db_info,
                                                                self.test_data['body_sql'])  # sql执行结果
        request_pull_template = self.serializer_info.get('request_pull_template')  # 获取出参参数模板
        self.test_data['body_data'] = self.get_out_dict_data(request_pull_template)  # 获取请求体数据

    # 获取断言数据
    def get_assert_data(self):
        if self.res.status: return
        sql_template = self.serializer_info.get('sql_assert_info').get('sql_template') if self.serializer_info.get(
            'sql_assert_info') else None  # sql模板
        if sql_template:
            request_sql_template = self.serializer_info.get('assert_sql_template')  # 获取入参sql模板 是一个字典
            db_info = self.serializer_info.get('sql_assert_info').get('db_info')
            db_type = self.serializer_info.get('sql_assert_info').get('db_type')
            db_class = DB_TYPES.get(db_type)
            self.test_data['assert_sql_dict'] = self.get_out_dict_data(request_sql_template)  # sql模板需要插入的数据
            self.test_data['assert_sql'] = self.get_out_sql_data(self.test_data['assert_sql_dict'],
                                                                 sql_template)  # 合成sql
            self.test_data['assert_sql_data'] = self.exe_sql_data(db_class, db_info,
                                                                  self.test_data['assert_sql'])  # sql执行结果
        request_pull_template = self.serializer_info.get('assert_pull_template')  # 获取出参参数模板
        self.test_data['assert_data'] = self.get_out_dict_data(request_pull_template)  # 获取请求体数据

    # 发起请求
    def api_request(self):
        if self.res.status: return
        method = self.test_data['method']
        url = self.test_data['url']
        data = self.test_data['body_data']
        headers = self.test_data['headers']
        request_obj = HttpRequest(method, url, data, headers)
        request_obj.http_request()
        self.test_data['response_data'] = request_obj.response_data
        res = request_obj.res
        if res.status:
            self.res = res

    # 数据对比函数
    def assert_func(self):
        if self.res.status: return
        assert_data = self.test_data['assert_data']  # 断言数据
        response_data = self.test_data['response_data']  # 响应数据
        tb = AssertTool(assert_data, response_data, self.show_status)
        tb.run()
        res = tb.res
        if res.status:
            self.res = res
        else:
            self.test_data['result_data'] = tb.dict()

    # 执行结果 'results': ((1, "通过"), (2, "不通过"), (3, "未执行"), (4, "执行失败"))
    def get_results(self):
        obj = self.test_data.get('result_data')
        if obj:
            if obj.get('assert_status'):
                self.results = 1
            else:
                self.results = 2
        else:
            self.results = 4
        self.test_data['results'] = self.results

    # 保存测试数据
    def save_data(self):
        if self.res.status:
            self.test_data['result_data'] = {
                'status': self.res.status,
                'msg': self.res.msg,
                'error': self.res.error
            }
        serializer = self.serializer
        queryset = self.queryset
        test_data = self.test_data
        if self.cases_status:
            self.queryset.results = self.test_data.get('results')
            self.queryset.save()
        else:
            res = SaveData(serializer, queryset, test_data).save_data()
            if res.status:
                self.res = res

    def run(self):
        self.get_project_info()
        self.get_method()
        self.get_url()
        self.get_headers()
        self.get_body()
        self.api_request()
        self.get_assert_data()
        self.assert_func()
        self.get_results()
        self.save_data()
        # self.res.data = self.data_warehouse
        #
        # return self.res
